﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;
using System.Xml;
using Higgs.Web.AtomPub.Attributes;
using Higgs.Web.AtomPub.Configurations;
using Higgs.Web.AtomPub.Models;

namespace Higgs.Web.AtomPub
{
    public class AtomPublishingController : Controller
    {
        public IEntryRepository EntryRep { get; set; }
        public IMediaRepository MediaRep { get; set; }

        public AtomPublishingController(IEntryRepository entryRep, IMediaRepository mediaRep)
        {
            EntryRep = entryRep;
            MediaRep = mediaRep;
        }

        public static void SetupRouteTable(RouteCollection routes, AtomPubConfigSection setting)
        {
            var controllerName = typeof(AtomPublishingController).Name.Replace("Controller", "");
            
            routes.MapRoute("AtomPub", setting.RoutePath, new {controller = controllerName, action = "Service", id = UrlParameter.Optional});
            routes.MapRoute("AtomPub_Feed", setting.Feed.RoutePath, new {controller = controllerName, action = "Feed", id = UrlParameter.Optional});
            routes.MapRoute("AtomPub_Media", setting.Media.RoutePath, new {controller = controllerName, action = "Media", id = UrlParameter.Optional});

            routes.IgnoreRoute(setting.Media.StaticPath + "/{*staticMedia}");
        }

        public virtual ActionResult Service()
        {
            return RenderHelpers.RenderService();
        }

        #region Feed
        
        [HttpGet]
        [NotRequireParameter("id")]
        public virtual ActionResult Feed()
        {
            return Feed(1);
        }

        [HttpGet]
        [RequireParameter("id", typeof(int))]
        public virtual ActionResult Feed(int id)
        {
            // TODO: Support page size from WLW.
            var setting = AtomPubConfigSection.Current;
            var pageSize = setting.Feed.PageSize;
            var entries = EntryRep.GetEntryList(id - 1, pageSize, false, User.Identity);
            var lastUpdate = EntryRep.GetLastUpdated(false, User.Identity);
            var totalPage = Math.Round(EntryRep.Count(User.Identity)/(double) pageSize);

            return entries.Render(HttpContext, lastUpdate, totalPage > id ? setting.Feed.RoutePath.Replace("{id}", (id + 1).ToString()) : null, true);
        }
        
        [HttpGet]
        [RequireParameter("id", typeof(Guid))]
        public virtual ActionResult Feed(Guid id)
        {
            var setting = AtomPubConfigSection.Current;
            var entry = EntryRep.GetEntry(id, User.Identity);
            
            return entry.Render(HttpContext, true);
        }

        [HttpPost]
        [AtomAuthroize]
        [ActionName("Feed")]
        public virtual ActionResult CreateFeed(IEntry entry)
        {
            var setting = AtomPubConfigSection.Current;
            EntryRep.CreateEntry(entry, HttpContext, User.Identity);

            var result = entry.Render(HttpContext, true);
            result.StatusCode = 0xc9;
            result.StatusDescription = "Created";
            result.Headers.Add("Location", setting.Feed.AbsolutePath + "/" + entry.Id);

            return result;
        }

        [HttpPut]
        [AtomAuthroize]
        [ActionName("Feed")]
        public virtual ActionResult EditFeed(Guid id, IEntry entry)
        {
            var setting = AtomPubConfigSection.Current;
            EntryRep.UpdateEntry(HttpContext, id, entry.Title, entry.ContentHtml, entry.PublishedDate, new string[]{}, entry.Draft,  User.Identity);

            return entry.Render(HttpContext, true);
        }

        [HttpDelete]
        [AtomAuthroize]
        [ActionName("Feed")]
        public virtual ActionResult DeleteFeed(Guid id)
        {
            EntryRep.DeleteEntry(id, HttpContext, User.Identity);

            return new EmptyResult();
        }
        
        #endregion

        #region Media
        
        [HttpGet]
        [RequireParameter("id", typeof(Guid))]
        public virtual ActionResult Media(Guid id)
        {
            var setting = AtomPubConfigSection.Current;
            var mediaItem = MediaRep.GetMediaLink(id, User.Identity);
            
            return mediaItem.Render(HttpContext);
        }

        [HttpPost]
        [NotRequireParameter("id")]
        [AtomAuthroize]
        [ActionName("Media")]
        public virtual ActionResult CreateMedia()
        {
            var setting = AtomPubConfigSection.Current;
            var mediaId = ParseSlug();
            var mediaItem = MediaRep.CreateMedia(HttpContext, Request.ContentType, Request.InputStream, mediaId, User.Identity);
            var result = mediaItem.Render(HttpContext);
            result.StatusCode = 0xc9;
            result.StatusDescription = "Created";
            result.Headers.Add("Location", HttpContext.ToAbsoluteUrl("~/" + setting.Media.Path + "/" + mediaItem.Id));

            return result;
        }

        [HttpPut]
        [AtomAuthroize]
        [ActionName("Media")]
        public virtual ActionResult EditMedia(Guid id)
        {
            var setting = AtomPubConfigSection.Current;
            var mediaId = ParseSlug();
            var mediaItem = MediaRep.UpdateMedia(HttpContext, id, Request.ContentType, Request.InputStream, User.Identity);

            return mediaItem.Render(HttpContext);
        }

        [HttpDelete]
        [AtomAuthroize]
        [ActionName("Media")]
        public virtual ActionResult DeleteMedia(Guid id)
        {
            MediaRep.DeleteMediaLink(id, HttpContext, User.Identity);

            return new EmptyResult();
        }

        #endregion
        
        #region Local Function

        protected virtual string ParseSlug()
        {
            var str2 = Request.Headers["slug"];
            if (string.IsNullOrEmpty(str2)) return null;

            var list = new List<byte>();
            var num = 0;

            while (num < str2.Length)
            {
                if (str2[num] == '%')
                {
                    if ((num + 2) >= str2.Length) break;

                    list.Add(Convert.ToByte(str2.Substring(num + 1, 2), 0x10));
                    num += 3;
                }
                else
                {
                    list.Add((byte) str2[num]);
                    num++;
                }
            }

            var result = Encoding.UTF8.GetString(list.ToArray());

            return result.Contains("[") ? result.Substring(0, result.IndexOf('[')) : result;
        }

        #endregion
    }
}
